/**
 * 
 */
package inf.tests;

import inf.booksManagement.Book;
import inf.dvdsManagement.Dvd;
import inf.exceptions.AllSpecimensBooked;
import inf.exceptions.BadParametersException;
import inf.exceptions.BookExistsException;
import inf.exceptions.BookedSpecimenException;

import inf.exceptions.LoanExistsException;
import inf.exceptions.MediaExistsException;
import inf.exceptions.NotLentMediaException;
import inf.exceptions.SpecimenExistsException;
import inf.exceptions.SubscriberExistsException;
import inf.exceptions.SubscriberWithLoansException;
import inf.exceptions.TooManyBooksException;
import inf.exceptions.TooManyLoansException;
import inf.hibernateUtils.HibernateUtil;
import inf.loansManagement.Booking;
import inf.loansManagement.Loan;
import inf.main.Library;
import inf.mediasManagement.Media;
import inf.mediasManagement.MediaDAO;
import inf.specimensManagement.Specimen;
import inf.subscribersManagement.Subscriber;
import inf.subscribersManagement.SubscriberDAO;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Before;
import org.junit.Test;


import static org.junit.Assert.*;

/**
 * @author  Fabre, Malric
 */
public class NewTests {

	private Library library;
	public static final int nbBOOK = 50;
	public static final int nbSPECBOOK = 3;
	public static final int nbDVD = 20;
	public static final int nbSPECDVD = 2;

	@Before
	public void beforeTests() throws BadParametersException, MediaExistsException, SubscriberExistsException
	{
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();

		library = new Library();

		ArrayList<String> authors = new ArrayList<String>() {{ add("Author 1"); add("Author 2"); add("Author 3"); }};
		ArrayList<String> authors2 = new ArrayList<String>() {{ add("AuthorDVD 1"); add("AuthorDVD 2"); add("AuthorDVD 3"); }};

		for(int i = 0; i < nbBOOK; i++){
			library.addMedia(new Book("Book " + i, new GregorianCalendar(),  "03212022" + i, nbSPECBOOK, authors));
		}
		for(int i = 0; i < nbDVD; i++){
			library.addMedia(new Dvd("Dvd" + i, new GregorianCalendar(),  "05552022"+i, nbSPECDVD, authors2));
		}
		
		library.addSubscriber(new Subscriber("Ambroise","Malric", new GregorianCalendar(1987, Calendar.JULY, 10), new GregorianCalendar(1995, Calendar.MAY, 02)));
		library.addSubscriber(new Subscriber("Arnaud","Fabre", new GregorianCalendar(1990, Calendar.MAY, 31), new GregorianCalendar(2012, Calendar.MAY, 28)));
		library.addSubscriber(new Subscriber("Vincent","Airo", new GregorianCalendar(1960, 12, 13), new GregorianCalendar(1990, Calendar.MAY, 28)));
		library.addSubscriber(new Subscriber("Vincent","Dupont", new GregorianCalendar(1965, 12, 13), new GregorianCalendar(1994, Calendar.MAY, 28)));
		library.addSubscriber(new Subscriber("Marc","Durant", new GregorianCalendar(1980, 12, 13), new GregorianCalendar(1998, Calendar.MAY, 28)));
		library.addSubscriber(new Subscriber("Antoine","Francois", new GregorianCalendar(1985, 12, 13), new GregorianCalendar(1995, Calendar.MAY, 28)));

		System.out.println("Before test OK\n");

		t.commit();
	}
	
	@Test
	public void nullTest(){
		assertTrue(library.getNbMedia() == nbDVD + nbBOOK);
		for(int i = 0; i < nbBOOK + nbDVD; i++){
			Media media = library.getMedia(i);
			if(media.getType() == "Book")
				assertTrue(media.getNbCreatedSpecimen() == nbSPECBOOK);
			if(media.getType() == "Dvd")
				assertTrue(media.getNbCreatedSpecimen() == nbSPECDVD);
		}

		System.out.println("Null test OK\n");
	}

	@Test
	public void addSpecimenMediasTest() throws BadParametersException, MediaExistsException 
	{
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();
		
		library.addSpecimen(new Specimen(library.getMedia(0)));
		library.addSpecimen(new Specimen(library.getMedia(0)));
		library.addSpecimen(new Specimen(library.getMedia(0)));
		System.out.println("Ajout de 3 exemplaire de " + library.getMedia(0).toString() + "\n");

		library.addSpecimen(new Specimen(library.getMedia(1)));
		library.addSpecimen(new Specimen(library.getMedia(1)));
		System.out.println("Ajout de 2 exemplaire de " + library.getMedia(1).toString() + "\n");

		assertTrue(library.getMedia(0).getNbCreatedSpecimen() == nbSPECBOOK + 3);
		assertTrue(library.getMedia(1).getNbCreatedSpecimen() == nbSPECBOOK + 2);

		t.commit();
	}

	@Test
	public void removeSpecimenMediasTest() throws BadParametersException, MediaExistsException 
	{
		// Ajout des specimens
		this.addSpecimenMediasTest();

		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();

		library.removeSpecimen(library.getMedia(0).getSpecimen(0));
		System.out.println("Suppression d'un exemplaire de " + library.getMedia(0).toString() + "\n");

		library.removeSpecimen(library.getMedia(1).getSpecimen(0));
		System.out.println("Suppression d'un exemplaire de " + library.getMedia(1).toString() + "\n");

		assertTrue(library.getMedia(0).getNbCreatedSpecimen() == nbSPECBOOK + 2);
		assertTrue(library.getMedia(1).getNbCreatedSpecimen() == nbSPECBOOK + 1);
		t.commit();
	}

	@Test
	public void removeMediasTest() throws BadParametersException, MediaExistsException 
	{
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();

		long nbMedia = library.getNbMedia();
		System.out.println("Suppression du media " + library.getMedia(0) + "\n");
		library.removeMedia(library.getMedia(0));

		assertTrue(library.getNbMedia() == nbMedia - 1);

		t.commit();
	}

	@Test
	public void removeSubscriberTest() throws BadParametersException, SubscriberWithLoansException, SubscriberExistsException, MediaExistsException 
	{
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();
		long nbSub = library.getNbSubscriber();

		System.out.println("Suppression de l'utilisateur : " + library.getSubscriber(0).toString() + "\n");
		library.removeSubscriber(library.getSubscriber(0));

		assertTrue(library.getNbSubscriber() == nbSub - 1);
		
		t.commit();
	}

	/**
	 * Teste les fonctionalites d'emprunts
	 * @throws BookedSpecimenException 
	 * @throws BadParametersException 
	 * @throws TooManyLoansException 
	 * @throws MediaExistsException 
	 * @throws SubscriberExistsException 
	 * @throws SpecimenExistsException 
	**/
	@Test
	public void testLoanMedia() throws BadParametersException, TooManyLoansException, BookedSpecimenException, MediaExistsException, SubscriberExistsException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
		
		Specimen spec = library.getMedia(0).getSpecimen(0);
		Subscriber user = library.getSubscriber(0);
		
		user.lend(spec);
		System.out.println("L'abonne " + user.toString() + " a emprunte le livre " + spec.toString() + "\n");

		t.commit();
		HibernateUtil.closeSession();

		// Verifications
		session = HibernateUtil.openSession();

		Specimen specimenDAO = inf.mediasManagement.MediaDAO.getSpecimen(spec.getId());
		Media mediaDAO = inf.mediasManagement.MediaDAO.get(library.getMedia(0).getId());
		Subscriber userDAO = inf.subscribersManagement.SubscriberDAO.get(user.getId());

		assertTrue(userDAO.getLoans().size() == 1);
		assertTrue(mediaDAO.getNbAvailableSpecimen() == nbSPECBOOK - 1);
		assertTrue(mediaDAO.getLentSpecimens() == 1);
		assertTrue(specimenDAO.getLoan() != null);

		HibernateUtil.closeSession();
	}

	@Test
	public void testProblemsLoan() throws MediaExistsException, BadParametersException, SubscriberExistsException, BookedSpecimenException, AllSpecimensBooked, BookExistsException, NotLentMediaException, TooManyLoansException, SpecimenExistsException, TooManyBooksException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
		
		Specimen spec = library.getMedia(0).getSpecimen(0);
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);
		Subscriber user3 = library.getSubscriber(2);

		user1.lend(spec);

		// Exemplaire deja emprunte
		System.out.println("L'abonne " + user1.toString() + " a emprunte le livre " + spec.toString() + "\n");
		try{
			user2.lend(spec);
		} catch (Exception e) {
			System.out.println(e.toString());
			System.out.println(e.getMessage());
		}

		// Tests quotas
		user1.lend( library.getMedia(1).getSpecimen(0));
		user1.lend( library.getMedia(2).getSpecimen(0));
		user1.lend( library.getMedia(3).getSpecimen(0));
		try{
			user1.lend( library.getMedia(4).getSpecimen(0));
		} catch (Exception e) {
			System.out.println(e.toString());
			System.out.println(e.getMessage());
		}
		// Quotas Dvd
		user1.lend( library.getMedia(50).getSpecimen(0));


		// Test emprunt deja reserve
		user2.book( library.getMedia(1));
		user2.endOfLoan(library.getMedia(1).getSpecimen(0));
		try{
			user3.lend( library.getMedia(1).getSpecimen(0));
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

		t.commit();
		HibernateUtil.closeSession();
	}
	
	/**
	 * Teste le retour d'emprunt
	 * @throws LoanExistsException 
	 * @throws TooManyLoansException 
	 * @throws SpecimenExistsException 
	**/
	@Test
	public void testReturnMedia() throws BadParametersException, MediaExistsException,
	SubscriberExistsException, BookExistsException, NotLentMediaException, BookedSpecimenException, LoanExistsException, TooManyLoansException, SpecimenExistsException{

		// Realisation de l'emprunt
		this.testLoanMedia();

		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
			
		Specimen spec = library.getMedia(0).getSpecimen(0);
		Subscriber user = library.getSubscriber(0);
		Loan loan = user.getLoans().get(0);
		System.out.println(loan.toString());

		// Retour du media
		user.endOfLoan(spec);
		System.out.println(loan.toString());
		
		System.out.println("Media bien retourne\n");

		t.commit();
		HibernateUtil.closeSession();
		
		// Verifications :
		session = HibernateUtil.openSession();

		Specimen specimenDAO = inf.mediasManagement.MediaDAO.getSpecimen(spec.getId());
		Media mediaDAO = inf.mediasManagement.MediaDAO.get(library.getMedia(0).getId());
		Subscriber userDAO = inf.subscribersManagement.SubscriberDAO.get(user.getId());
		Loan loanDAO = inf.loansManagement.LoanDAO.get(user.getLoans().get(0).getId());

		assertTrue(userDAO.getNumberOfBookLent() == 0);
		assertTrue(mediaDAO.getNbAvailableSpecimen() == nbSPECBOOK);
		assertTrue(mediaDAO.getLentSpecimens() == 0);
		assertTrue(specimenDAO.getLoan() == null);
		assertTrue(loanDAO.getReturned() == true);

		HibernateUtil.closeSession();
	}


	// test booking simple
	@Test
	public void testBooking1() throws BadParametersException, MediaExistsException, SubscriberExistsException, BookedSpecimenException, AllSpecimensBooked, TooManyLoansException, SpecimenExistsException, TooManyBooksException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
		
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);
		
		System.out.println("Emprunt de l'exemplaire 0 du media 0 (utilisateur 0)\n");

		user1.lend( library.getMedia(0).getSpecimen(0));

		System.out.println("Reservation du media 0 (utilisateur 1)\n");
		user2.book( library.getMedia(0));

		t.commit();

		session = HibernateUtil.openSession();

		Media mediaDAO = inf.mediasManagement.MediaDAO.get(library.getMedia(0).getId());
		Subscriber userDAO = inf.subscribersManagement.SubscriberDAO.get(user2.getId());
			
		HibernateUtil.closeSession();

		assertTrue(userDAO.getNumberOfMediaBooked() == 1);
		assertTrue(mediaDAO.getBookings().size() == 1);
	}

	// test booking simple avec retour d'exemplaire
	@Test
	public void testBooking2() throws BadParametersException, MediaExistsException, TooManyLoansException, BookedSpecimenException, TooManyBooksException, AllSpecimensBooked, NotLentMediaException, SubscriberExistsException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
		
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);

		System.out.println("Emprunt de l'exemplaire 0 du media 0 (utilisateur 0)\n");
		user1.lend( library.getMedia(0).getSpecimen(0));
		
		System.out.println("Reservation du media 0 (utilisateur 1)\n");
		user2.book( library.getMedia(0));
		
		System.out.println("Retour de l'exemplaire 0 du media 0 (utilisateur 0)\n");
		user1.endOfLoan(library.getMedia(0).getSpecimen(0));
		t.commit();

		session = HibernateUtil.openSession();

		Media mediaDAO = inf.mediasManagement.MediaDAO.get(library.getMedia(0).getId());
		Subscriber userDAO = inf.subscribersManagement.SubscriberDAO.get(user2.getId());
		Specimen specimenDAO = inf.mediasManagement.MediaDAO.getSpecimen(library.getMedia(0).getSpecimen(0).getId());

		HibernateUtil.closeSession();
		
		System.out.println("La reservation pour l'utilisateur 1 a commencee\n");
		assertTrue(userDAO.getNumberOfMediaBooked() == 1);
		assertTrue(mediaDAO.getBookings().size() == 0);
		assertTrue(specimenDAO.getBooking().getSubscriber().equals(user2));
	}

	// test booking simple avec emprunt 
	@Test
	public void testBooking3() throws BadParametersException, TooManyLoansException, BookedSpecimenException, MediaExistsException, TooManyBooksException, AllSpecimensBooked, NotLentMediaException, SubscriberExistsException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
		
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		library.removeSpecimen(library.getMedia(0).getSpecimen(1));
		
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);

		System.out.println("Emprunt de l'exemplaire 0 du media 0 (utilisateur 0)\n");
		user1.lend( library.getMedia(0).getSpecimen(0));
		
		System.out.println("Reservation du media 0 (utilisateur 1)\n");
		user2.book( library.getMedia(0));
		
		System.out.println("Retour de l'exemplaire 0 du media 0 (utilisateur 0)\n");
		user1.endOfLoan(library.getMedia(0).getSpecimen(0));
		
		System.out.println("Emprunt de l'exemplaire 0 du media 0 (utilisateur 1)\n");
		user2.lend(library.getMedia(0).getSpecimen(0));
		t.commit();

		session = HibernateUtil.openSession();

		Media mediaDAO = inf.mediasManagement.MediaDAO.get(library.getMedia(0).getId());
		Subscriber user1DAO = inf.subscribersManagement.SubscriberDAO.get(user1.getId());
		Subscriber user2DAO = inf.subscribersManagement.SubscriberDAO.get(user2.getId());
		Specimen specimenDAO = inf.mediasManagement.MediaDAO.getSpecimen(library.getMedia(0).getSpecimen(0).getId());

		HibernateUtil.closeSession();

		assertTrue(user2DAO.getNumberOfMediaBooked() == 0);
		assertTrue(user2DAO.getNumberOfBookLent() == 1);
		assertTrue(user1DAO.getNumberOfBookLent() == 0);
		assertTrue(mediaDAO.getBookings().size() == 0);
		assertTrue(specimenDAO.getLoan().getSubscriber().equals(user2));
	}

	// test booking avec problems
	@Test
	public void testBookingProblems() throws BadParametersException, TooManyLoansException, BookedSpecimenException, MediaExistsException, TooManyBooksException, AllSpecimensBooked, NotLentMediaException, SubscriberExistsException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
	
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);
		Subscriber user3 = library.getSubscriber(2);
		Subscriber user4 = library.getSubscriber(3);
		Subscriber user5 = library.getSubscriber(4);
		Subscriber user6 = library.getSubscriber(5);

		user1.lend( library.getMedia(0).getSpecimen(0));
		user1.lend( library.getMedia(1).getSpecimen(0));
		user1.lend( library.getMedia(2).getSpecimen(0));
		user1.lend( library.getMedia(3).getSpecimen(0));
		user1.lend( library.getMedia(4).getSpecimen(0));
		user1.lend( library.getMedia(5).getSpecimen(0));

		user2.book(library.getMedia(0));
		user2.book(library.getMedia(1));
		user2.book(library.getMedia(2));
		user2.book(library.getMedia(3));
		user2.book(library.getMedia(4));
		try {
			user2.book( library.getMedia(5));
		} catch(Exception e) {
			System.out.println(e.getMessage());
		}
		
		// Tous les exemplaires reserves :
		library.removeSpecimen(library.getMedia(15).getSpecimen(2));		

		user1.lend(library.getMedia(15).getSpecimen(0));
		user3.lend(library.getMedia(15).getSpecimen(1));

		user4.book(library.getMedia(15));
		user5.book(library.getMedia(15));
		try{
			user6.book(library.getMedia(15));
		}  catch(Exception e) {
			System.out.println(e.getMessage());
		}
		
		t.commit();
	}


	
	@Test
	public void testList(){
		System.out.println(library.listMedias());
		System.out.println("\n\nBooks :\n");
		System.out.println(library.listBooks());
		System.out.println("\n\nDvds : \n");
		System.out.println(library.listDvds());
	}

	@Test
	public void testHistorique()  throws BadParametersException, TooManyLoansException, BookedSpecimenException, MediaExistsException, TooManyBooksException, AllSpecimensBooked, NotLentMediaException, SubscriberExistsException {
		Session session = HibernateUtil.openSession();
		Transaction t = session.beginTransaction();	
	
		Subscriber user1 = library.getSubscriber(0);
		Subscriber user2 = library.getSubscriber(1);
//		Subscriber user3 = library.getSubscriber(2);
//		Subscriber user4 = library.getSubscriber(3);
//		Subscriber user5 = library.getSubscriber(4);
//		Subscriber user6 = library.getSubscriber(5);


		user1.lend(library.getMedia(0).getSpecimen(0));
		user1.lend(library.getMedia(1).getSpecimen(0));
		user1.lend(library.getMedia(2).getSpecimen(0));
		user1.lend(library.getMedia(3).getSpecimen(0));

		user2.lend(library.getMedia(4).getSpecimen(0));
		user2.lend(library.getMedia(5).getSpecimen(0));
		user2.lend(library.getMedia(6).getSpecimen(0));
		user2.lend(library.getMedia(7).getSpecimen(0));

		user1.endOfLoan(library.getMedia(0).getSpecimen(0));
		user1.endOfLoan(library.getMedia(1).getSpecimen(0));
		user1.endOfLoan(library.getMedia(2).getSpecimen(0));
		user1.endOfLoan(library.getMedia(3).getSpecimen(0));
		
		user2.endOfLoan(library.getMedia(4).getSpecimen(0));
		user2.endOfLoan(library.getMedia(5).getSpecimen(0));
		user2.endOfLoan(library.getMedia(6).getSpecimen(0));
		user2.endOfLoan(library.getMedia(7).getSpecimen(0));

		user2.lend(library.getMedia(0).getSpecimen(0));
		user2.lend(library.getMedia(1).getSpecimen(0));
		user2.lend(library.getMedia(2).getSpecimen(0));

		t.commit();
		
		// Affichage de l'historique
		session = HibernateUtil.openSession();
		
		Subscriber user1DAO = inf.subscribersManagement.SubscriberDAO.get(user1.getId());
		Subscriber user2DAO = inf.subscribersManagement.SubscriberDAO.get(user2.getId());
		Specimen specimenDAO = inf.mediasManagement.MediaDAO.getSpecimen(library.getMedia(0).getSpecimen(0).getId());
		
		System.out.println("Emprunts de l'utilisateur 0");
		System.out.println(user1DAO.history().toString());
		System.out.println("\n");
		
		System.out.println("Emprunts de l'utilisateur 1");
		System.out.println(user2DAO.history().toString());
		System.out.println("\n");
		
		System.out.println("Emprunts de l'exemplaire 0 du m�dia 0");
		System.out.println(specimenDAO.history().toString());
		System.out.println("\n");
		
		HibernateUtil.closeSession();
	}
	
}
